<template>
  <div class="file-upload">
      <button class="btn btn-primary" @click.prevent="triggerUpload">
          <span v-if="fileStatus === 'loading'">上传中...</span>
          <span v-else-if="fileStatus === 'sucess'">上传成功</span>
          <span v-else-if="fileStatus === 'error'">上传失败</span>
          <span v-else>上传文件</span>
          </button>
      <input type="file"
       class="file-input d-none"
       ref="fileInput"
       @change="handleFileChange">
  </div>
</template>

<script lang='ts'>
/* 上传文件 */
import {defineComponent,ref,PropType} from 'vue'

import axios from '@/api/request'

// 定义上传的状态
type UploaderStatus = 'ready' | 'loading' | 'sucess' | 'error'

// 自定义检查，是一个函数，返回的是布尔值
type checkFunction = (file: File) => boolean

export default defineComponent({
props: {
    action: {
        type:String,
        required: true
    },
    /* 上传前的一系列检查 */
    boforeUpload: {
        type: Function as PropType<checkFunction>
    }
},
// 定义要暴露的上传成功事件，上传失败事件
emits: ['file-uploaded','file-uploaded-error'],
setup(props,context){

    // 绑定ref,获得input元素的节点
    const fileInput = ref<null | HTMLInputElement>(null)
    
    // 创建上传状态的响应式对象
    const fileStatus = ref<UploaderStatus>('ready')

    const triggerUpload  = () => {
        //当input节点存在的时候，就触发点击事件
        if (fileInput.value) {
           fileInput.value.click() 
        }
    }

    // input 的change事件
    const handleFileChange = ((e:Event) => {
        // 获取里面的文件,这样是为了获得file属性
        const currentTarget = e.target as HTMLInputElement
        // 如果条件为真，说明已经选择了文件，可以上传
        if (currentTarget.files) {
            // 因为currentTarget.files不是一个数组，需要手动转换
            const fiels = Array.from(currentTarget.files)

            // 如果存在该属性，就做上传前的一系列检查
            if (props.boforeUpload) {
                const result = props.boforeUpload(fiels[0])

                // 如果不满足条件，就不执行下面的程序
                if (!result) {
                    return
                }
            }
            fileStatus.value = 'loading'
            const formData = new FormData
            formData.append('file',fiels[0])
            axios.post(props.action ,formData,{
                headers: {
                    'Content-Type': 'multipart/form-data'
                }
            }).then(res => {
                fileStatus.value = 'sucess'
                // 上传成功后，暴露成功事件
                context.emit('file-uploaded',res.data)
                
            }).catch(err => {
                fileStatus.value = 'error'
                context.emit('file-uploaded-error',{err})
            }).finally(() => {
                if (fileInput.value) {
                    fileInput.value.value = ''
                }
            })

        }
    })


    return {
        fileInput,
        triggerUpload,
        handleFileChange,
        fileStatus
    }
}
})
</script>

<style>

</style>